package cn.wolfcode.shiro;

import cn.wolfcode.domain.Employee;
import cn.wolfcode.mapper.EmployeeMapper;
import cn.wolfcode.mapper.PermissionMapper;
import cn.wolfcode.mapper.RoleMapper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 自定义数据源：提供数据给shiro使用的
 */
@Component
public class CrmRealm extends AuthorizingRealm{

    @Autowired
    private EmployeeMapper employeeMapper;


    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired //注入spring容器中的凭证匹配器
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        super.setCredentialsMatcher(credentialsMatcher);
    }

    /**
     * 提供认证信息的数据
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //通过token获取到用户名
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
        String username = usernamePasswordToken.getUsername();
        //查询数据库中是否存在该用户名
        Employee employee = employeeMapper.selectByName(username);
        if(employee!=null){
            //如果存在，就把用户的用户名，密码封装到AuthenticationInfo中，最后返回给shiro使用
            //第一个参数员工对象（方便后续直接通过subject来获取），第二个参数是用户真正的密码，第三个参数当前数据源的名字（对于我们来说现在没用）
            return new SimpleAuthenticationInfo(employee,employee.getPassword(),
                    ByteSource.Util.bytes(employee.getName()),this.getName()); //第三个参数就是盐（跟注册时使用的盐相同）
        }
        //用户名不存在，返回null
        return null;
    }


    /**
     * 提供授权信息数据(当前登录用户拥有的)
     * 每一次shiro需要进行权限判断（编程式，注解式，标签式），都会调用该方法获取员工的数据来做判断
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("===================");
        //获取当前登录用户的对象
       /* 如果框架的参数没有提供给我们，就可以用工具来获取
        Subject subject = SecurityUtils.getSubject();
        Employee employee = (Employee)subject.getPrincipal();*/

        //框架有提供参数，直接拿来用即可
        Employee employee = (Employee)principals.getPrimaryPrincipal();
        //info对象中的数据就是当前登录用户的权限和角色的信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //判断是否为超级管理员
        if(!employee.isAdmin()){
            //根据员工id查询员工的角色编码集合
            List<String> roles = roleMapper.selectSnByEmpId(employee.getId());
            info.addRoles(roles);
            //根据员工id查询员工的权限表达式集合
            List<String> expressions = permissionMapper.selectExpressionByEmpId(employee.getId());
            info.addStringPermissions(expressions);
        }else{
            info.addStringPermission("*:*"); //所有权限，使用了通配符
            info.addRole("ADMIN"); //管理员角色, 可给也可以不给，给了就方便直接使用subject就可以判断是否管理员
        }

        return info;
    }



}
